﻿using Furion.CMS.Core;
using Furion.CMS.Core.EventSource;
using Furion.CMS.Core.Handlers;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.EventBus;
using Furion.TaskScheduler;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Domain
{
    public class RoleAuthorizedFormatHandler<T> : AuditLogFormatHandler
        where T : class
    {
        public override string GetRowKey(DbContext context, object entityValues, params string[] formatArgs)
        {
            if (entityValues is PropertyValues values)
            {
                var rid = values.GetValue<int>(nameof(RoleAuthorized.RoleId));
                var uid = values.GetValue<int>(nameof(RoleAuthorized.UserId));

                var role = context.Find<RoleInfo>(rid);
                if (role == null) return "未知";
                var user = context.Find<UserInfo>(uid);

                return $"{role.Name}授权-{user.NickName}";
            }
            return "未知";
        }

        public override string[] GetChangeValue(DbContext context, object oldValue, object newValue)
        {
            if (typeof(T) == typeof(RoleInfo))
            {
                int.TryParse(oldValue?.ToString(), out var oldId);
                int.TryParse(newValue?.ToString(), out var newId);

                var oldObj = context.Find<RoleInfo>(oldId);
                var newObj = context.Find<RoleInfo>(newId);

                return new string[2] { oldObj?.Name ?? "无", newObj?.Name ?? "无" };
            }
            else
            {
                int.TryParse(oldValue?.ToString(), out var oldId);
                int.TryParse(newValue?.ToString(), out var newId);

                var oldObj = context.Find<UserInfo>(oldId);
                var newObj = context.Find<UserInfo>(newId);

                return new string[2] { oldObj?.NickName ?? "无", newObj?.NickName ?? "无" };
            }
        }
    }


    [OperateRecord("角色授权")]
    public class RoleAuthorized : IEntity, IEntityTypeBuilder<RoleAuthorized>,
        IEntitySeedData<RoleAuthorized>, // 种子数据
        IEntityChangedListener<RoleAuthorized> // 数据变更监听
    {
        public RoleAuthorized()
        {
            CreatedTime = DateTimeOffset.UtcNow;
        }

        /// <summary>
        /// 角色id
        /// </summary>
        [OperateRecord("角色", true, typeof(RoleAuthorizedFormatHandler<RoleInfo>))]
        public int RoleId { get; set; }
        /// <summary>
        /// 角色
        /// </summary>
        public virtual RoleInfo Role { get; set; }
        /// <summary>
        /// 人员id
        /// </summary>
        [OperateRecord("授权人员", typeof(RoleAuthorizedFormatHandler<UserInfo>))]
        public int UserId { get; set; }
        /// <summary>
        /// 人员
        /// </summary>
        public virtual UserInfo User { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTimeOffset CreatedTime { get; set; }

        public void Configure(EntityTypeBuilder<RoleAuthorized> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.UseDefaultTableNameDefine();

            entityBuilder.HasIndex(i => new { i.RoleId, i.UserId });
        }

        public IEnumerable<RoleAuthorized> HasData(DbContext dbContext, Type dbContextLocator)
        {
            return new List<RoleAuthorized>
            {
                new RoleAuthorized{ RoleId=1, UserId=1 }
            };
        }

        public void OnChanged(RoleAuthorized newEntity, RoleAuthorized oldEntity, DbContext dbContext, Type dbContextLocator, EntityState state)
        {
            SpareTime.DoIt(() =>
            {
                // 创建作用域用于通知缓存更新
                Scoped.Create((_, scope) =>
                {
                    var services = scope.ServiceProvider;
                    // 获取数据库上下文
                    var dbContext = Db.GetDbContext(services);
                    var operationType = CacheOperationType.Add;
                    if (state == EntityState.Detached)
                    {// 移除
                        operationType = CacheOperationType.Remove;
                    }
                    // 触发事件
                    var eventPublisher = services.GetService<IEventPublisher>();
                    // 补充查询角色信息
                    newEntity.Role = newEntity.Role ?? dbContext.Find<RoleInfo>(newEntity.RoleId);
                    dbContext.Attach(newEntity.Role).Collection(c => c.Permissions).Load();

                    // 获取当前角色下的权限依赖
                    var dependentResList = newEntity.Role.Permissions.Where(t => !string.IsNullOrWhiteSpace(t.DependentResources))
                        .SelectMany(s => s.DependentResources.Split(new String[] { "," }, StringSplitOptions.RemoveEmptyEntries));

                    var resourcePayload = string.Format(CacheKeyConsts.PermissionResourceValue, newEntity.Role.Code, newEntity.UserId);
                    var changeEvents = dependentResList.Select(s => new OnPermissionDataItemChange(operationType, string.Format(CacheKeyConsts.PermissionResource, s, ""), new string[] { resourcePayload }));
                    // 通知缓存更新
                    eventPublisher?.PublishAsync(new ChannelEventSource(EventIdConsts.PermissionDataItemManyChange, changeEvents));
                });
            });


        }
    }
}
